import { _decorator, Component, Node, Prefab, NodePool, Vec3, UITransform, instantiate, Sprite, director, Label, v3, input, Input } from 'cc';
import { BLOCK_SHAPE } from "./Shape";
import { Music } from "./Music";
const { ccclass, property } = _decorator;

enum GameState {//定义游戏状态
  GS_INIT,
  GS_PLAYING,
  GS_END
}

@ccclass("GameController")
export class GameController extends Component {
  //#region
  @property(Prefab) tilePrefab!: Prefab;
  // 开始的UI
  @property(Node) startMenu?: Node;
  // 游戏界面
  @property(Node) shapeBoard!: Node;
  // 预览区
  @property(Node) next!: Node;
  // 游戏得分
  @property(Label) score!: Label;
  // 音乐开关
  @property(Music) music?: Music;
  // gameOver
  @property(Sprite) gameOver!: Sprite;
  // gamePruse
  @property(Sprite) gamePruse!: Sprite;

  // 方块节点池
  private tilePool: NodePool = new NodePool();
  //保存当前形状所有方块
  private shapeTileArray?: Node[];
  // 保存下一个形状
  private nextShapeArray?: Node[];
  // 行
  private row: number = 20;
  // 列
  private col: number = 10;
  // 方块宽高
  private tileWidth: number = 40;
  private tileHight: number = 40;
  // 横向起始位置
  private startX: number = Math.floor(Math.random() * (this.col - 7)) + 3; //(3~4)
  // 纵向起始位置
  private startY: number = 0;
  // 形状名字
  private shapeName?: string;
  // 当前形状名字
  private curShapeName?: string;
  // 形状索引
  private num?: number = 0;
  // 保存已经下落完毕的方块
  private confirmedTileArray?: Node[];
  // 计分器
  private scoring?: number;
  //#endregion

  onLoad() {

  }

  init() {
    if (this.startMenu) {
      this.startMenu.active = true;
    }
    this.scoring = 0;
    this.confirmedTileArray = [];
  }

  start() {
    // 游戏状态
    this.setCurState(GameState.GS_INIT);
  }

  // 防止用户操作角色
  // setInputActive(active: boolean) {
  //   if (active) {
  //     input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this);
  //   } else {
  //     input.off(Input.EventType.MOUSE_UP, this.onMouseUp, this);
  //   }
  // }

  playing(): void {
    // 隐藏开始UI
    if (this.startMenu) {
      this.startMenu.active = false;
    }
    // 判断是否已暂停,返回布尔值
    director.isPaused();

    // 游戏界面初始化形状
    this.shapeTileArray = this.makeShape();
    this.curShapeName = this.shapeName;
    for (let i = 0; i < this.shapeTileArray.length; i++) {
      this.shapeTileArray[i].parent = this.shapeBoard; //设置父节点
    }
    // 预览形状
    this.nextShape();

    // 添加计时器
    this.schedule(() => {
      this.moveDown();
    }, 0.5);
  }
  //设置当前游戏状态
  setCurState(value: GameState) {
    switch (value) {
      case GameState.GS_INIT:
        this.init();
        break;
      case GameState.GS_PLAYING:
        this.playing();
        break;
    }
  }

  // 生成形状
  makeShape() {
    // 定义存放生成形状的数组
    let shape: Node[] = [];
    let shapeData = [];

    // 随机获取形状
    shapeData = this.getShapeCoords();
    // 遍历获取到的形状坐标(遍历四个节点)
    for (let i = 0; i < shapeData.length; i++) {
      for (let j = 0; j < shapeData[i].length; j++) {
        // 遍历节点中的四个数
        if (shapeData[i][j]) {
          const node = this.square();
          const x = i * this.tileWidth;
          const y = -j * this.tileWidth;
          node.position = v3(x, y, 0);
          shape.push(node);
        }
      }
    }
    return shape;
  }

  // 预览区
  nextShape() {
    this.nextShapeArray = [];
    this.nextShapeArray = this.makeShape();

    for (let i = 0; i < this.nextShapeArray.length; i++) {
      this.nextShapeArray[i].parent = this.next; //设置父节点
    }
  }

  // 游戏区
  game() {
    this.shapeTileArray = [];
    this.shapeTileArray = this.nextShapeArray; //里边是节点
    this.curShapeName = this.shapeName; //将当前的形状名和索引名存储

    let x, y; //形状的原始坐标
    for (let i = 0; i < this.shapeTileArray.length; i++) {
      this.shapeTileArray[i].parent = this.shapeBoard; //设置父节点
      // TODO
      x = this.shapeTileArray[i].getPosition().x / this.tileWidth;
      y = this.shapeTileArray[i].getPosition().y / this.tileWidth;
      this.shapeTileArray[i].setPosition(
        (x + this.startX) * this.tileWidth,
        (y + this.startY) * this.tileHight
      );
    }
  }

  // 生成新方块
  square() {
    let tile: Node | null = null;
    // 如果节点池有从节点池获取
    if (this.tilePool.size() > 0) {
      tile = this.tilePool.get();
    }
    // 没有复制预制体（实例化）
    tile = instantiate(this.tilePrefab);
    tile.active = true;
    return tile;
  }

  // 随机获取某个形状的某种形态坐标，根据该坐标生成其他方块
  getShapeCoords() {
    // 随机获取形状(名字)
    const shape = Object.keys(BLOCK_SHAPE);
    this.shapeName = shape[Math.floor(Math.random() * shape.length)];
    // 获取形状
    const coordsArray = BLOCK_SHAPE[this.shapeName][0];
    return coordsArray; //返回的是一个具体形状
  }

  // 开始游戏
  onStartBtnClicked() {
    this.setCurState(GameState.GS_PLAYING);
  }

  // 下落
  moveDown() {
    // 判断是否暂停
    if (director.isPaused()) {
      return;
    }

    // 往下移动一步
    for (let i = this.shapeTileArray.length - 1; i >= 0; i--) {
      const shape_node = this.shapeTileArray[i];
      let x = Math.round(shape_node.position.x); //将形状数组中的x赋值
      let y = Math.round(shape_node.position.y); //将形状数组中的y赋值

      // 如果到底部则不再下落
      let shapeY = Math.abs(y) + this.tileHight;
      if (shapeY >= this.shapeBoard.getComponent(UITransform).height) {
        this.shapeTileArray.forEach((element) => {
          this.confirmedTileArray.push(element); //将确定的方块放入this.confirmedTileArray
        });
        this.removeLines(); //消除方块
        this.game();
        this.nextShape();
        return false;
      }

      // 如果与其他方块重合，则不在下降
      for (let j = 0; j < this.confirmedTileArray.length; j++) {
        const confirmed_node = this.confirmedTileArray[j];
        let confirmedX: number = Math.round(confirmed_node.position.x);
        let confirmedY: number = Math.round(confirmed_node.position.y);

        // 当已经存在的方块和下落方块相遇
        if (confirmedX == x && confirmedY == y - this.tileHight) {
          // 将确定的方块放入this.confirmedTileArray
          this.shapeTileArray.forEach((element) => {
            this.confirmedTileArray.push(element);
          });

          if (this.judgeLose()) {
            this.lose();
          } else {
            this.removeLines(); //消除方块
            this.game();
            this.nextShape();
          }
          return false;
        }
      }
    }

    // 都没问题，当前形状中方块正常下降
    for (let i = 0; i < this.shapeTileArray.length; i++) {
      const node = this.shapeTileArray[i];
      node.setPosition(node.position.x, node.position.y - this.tileHight);
    }
    return true;
  }

  // 方块消除
  removeLines() {
    // 某一行所有方块宽度总和等于游戏界面宽度
    let lines = []; //记录被消除的行编号
    for (let i = this.row; i >= 0; i--) {
      //从下往上
      let tempWidth = 0; //是否进行消除
      let tempTile: Node[] = []; //存储某一行要被消除的方块预制
      let row_y = Math.round(-i * this.tileHight); //当前行y值

      // 判断confirmedTileArray中方块y值跟当前行的y值是否相同
      for (let j = 0; j < this.confirmedTileArray.length; j++) {
        //从下往上
        let confirmedY = Math.round(this.confirmedTileArray[j].position.y);

        if (row_y == confirmedY) {
          tempTile.push(this.confirmedTileArray[j]); //满足方块存储方块
          tempWidth += this.tileWidth; //增加tempWidth值
        }
      }

      // 判断tempWidth值是否等于（或超过）shapeBoard的宽度，若超过说明该行已被填满
      if (tempWidth >= this.shapeBoard.getComponent(UITransform).width) {
        lines.push(i);
        tempTile.forEach((e) => {
          //从confirmedTileArray中删除相关方块
          for (let j = 0; j < this.confirmedTileArray.length; j++) {
            if (e == this.confirmedTileArray[j])
              this.confirmedTileArray.splice(j, 1); //删除数组中已经消除的方块
          }
          this.tilePool.put(e); //回收方块
        });
      }
    }

    // 让其他未消除的方块下落
    if (lines.length) this.dropConfirmedTiles(lines);
  }

  // 让其他未消除的方块下落
  dropConfirmedTiles(lines) {
    //操作被消除的那一行
    for (let i = 0; i < lines.length; i++) {
      //行
      for (let j = 0; j < this.confirmedTileArray.length; j++) {
        let confirmedY: number = Math.round(
          this.confirmedTileArray[j].position.y
        );

        // 只有被消除行上方的方块才允许下落
        if (confirmedY <= -lines[i] * this.tileHight) {
          continue;
        }
        // 让y坐标每次减一个方块大小
        let node = this.confirmedTileArray[j];

        node.setPosition(
          node.position.x,
          node.position.y - lines.length * this.tileHight
        );
      }
      // 增加分数
      this.addScore();
      // this.music._audioSource.playOneShot(this.music.eatScoreAudio,0.5);//音乐
    }
  }

  // 计分
  addScore() {
    this.scoring += 100; //分数加一
    this.score.string = String(this.scoring); //将计分器数值给得分
  }
  // 左移
  leftBtn() {
    // 判断是否暂停
    if (director.isPaused()) {
      return;
    }

    // this.music._audioSource.playOneShot(this.music.moveAudio,0.5);

    for (let i = 0; i < this.shapeTileArray.length; i++) {
      const node = this.shapeTileArray[i];
      let other_x: number = Math.round(node.position.x - this.tileWidth);
      let other_y: number = Math.round(node.position.y);

      // 防止出界
      if (other_x < 0) {
        return;
      }

      // 如果与其他方块重合，则不能移动
      for (let j = 0; j < this.confirmedTileArray.length; j++) {
        let confirmedX: number = Math.round(
          this.confirmedTileArray[j].position.x
        );
        let confirmedY: number = Math.round(
          this.confirmedTileArray[j].position.y
        );
        if (confirmedX == other_x && confirmedY == other_y) {
          return;
        }
      }
    }
    // 当前形状中所有方块左移一步
    for (let i = 0; i < this.shapeTileArray.length; i++) {
      const node = this.shapeTileArray[i];
      node.setPosition(node.position.x - this.tileHight, node.position.y);
    }
  }

  // 右移
  rightBtn() {
    // 判断是否暂停
    if (director.isPaused()) {
      return;
    }

    // this.music._audioSource.playOneShot(this.music.moveAudio,0.5);

    for (let i = 0; i < this.shapeTileArray.length; i++) {
      let other_x: number = Math.round(
        this.shapeTileArray[i].position.x + this.tileWidth
      );
      let other_y: number = Math.round(this.shapeTileArray[i].position.y);

      // 防止出界
      if (other_x >= this.shapeBoard.getComponent(UITransform).width) {
        return;
      }

      // 如果与其他方块重合，则不能移动
      for (let j = 0; j < this.confirmedTileArray.length; j++) {
        let confirmedX: number = Math.round(
          this.confirmedTileArray[j].position.x
        );
        let confirmedY: number = Math.round(
          this.confirmedTileArray[j].position.y
        );
        if (confirmedX == other_x && confirmedY == other_y) {
          return;
        }
      }
    }
    // 当前形状中所有方块左移一步
    for (let i = 0; i < this.shapeTileArray.length; i++) {
      const node = this.shapeTileArray[i];
      node.setPosition(node.position.x + this.tileHight, node.position.y);
    }
  }

  // 旋转
  roBtn() {
    // 判断是否暂停
    if (director.isPaused()) {
      return;
    }

    let temp: number = this.num; //将形状索引存在临时变量中

    if (BLOCK_SHAPE[this.curShapeName].length == 1) return;
    else {
      if (this.num + 1 == BLOCK_SHAPE[this.curShapeName].length) this.num = 0;
      else this.num += 1;
    }
    // 获取原来形状坐标
    let originalTile = this.shapeTileArray[0].position;
    // 获取旋转形状
    let coords = BLOCK_SHAPE[this.curShapeName][this.num]; //直接从形状组件中获取的

    let coordx: number;
    let coordy: number;
    let index: number = 0;

    for (let i = 0; i < coords.length; i++) {
      for (let j = 0; j < coords[i].length; j++) {
        if (coords[i][j]) {
          let node = this.shapeTileArray[index++];
          coordx = Math.round(i * this.tileWidth + originalTile.x);
          coordy = Math.round(-j * this.tileHight + originalTile.y);
          node.position = v3(coordx, coordy, 0);
        }
      }

      // 是否超出边界
      if (
        coordx < 0 ||
        coordx > this.shapeBoard.getComponent(UITransform).width ||
        Math.abs(coordy) >= this.shapeBoard.getComponent(UITransform).height
      ) {
        this.num = temp;
        return;
      }

      // 如果与其他已存在方块重合则不旋转
      for (let j = 0; j < this.confirmedTileArray.length; j++) {
        let confirmedX = Math.round(this.confirmedTileArray[j].position.x); //防止出现小数
        let confirmedY = Math.round(this.confirmedTileArray[j].position.y);
        if (confirmedX == coordx && confirmedY == coordy) {
          this.num = temp; //因为前边有this.num += 1
          return;
        }
      }
      console.log("旋转");
    }
  }

  // 一落到底
  dropBtn() {
    // 判断是否暂停
    if (director.isPaused()) {
      return;
    }
    // this.music._audioSource.playOneShot(this.music.moveAudio,0.5);
    while (true) {
      //直接下落
      let temp: boolean = this.moveDown();
      if (!temp) {
        //如果为false，跳出循环
        return;
      }
    }
  }

  // 游戏失败（方块超出游戏界面则游戏失败）
  judgeLose() {
    for (let i = 0; i < this.confirmedTileArray.length; i++) {
      // 循环confirmedTileArray，看哪个方块超出屏幕顶端（通过y值判断）
      for (let j = 0; j < this.shapeTileArray.length; j++) {
        let confirmedY: number = Math.max(
          Math.round(this.shapeTileArray[j].position.y)
        );

        // 如果有任何一个方块超出顶端，游戏结束
        if (confirmedY >= 0) {
          return true;
        }
        return false;
      }
    }
  }

  // 游戏失败后调用
  lose() {
    //this.unschedule(this.moveDown);//取消计时器
    this.unscheduleAllCallbacks();
    this.gameOver.node.active = true;
    // director.end();//退出游戏
    // 播放音效
    // this.music._audioSource.playOneShot(this.music.loseAudio,0.5);
    console.log("游戏结束");
  }
  // 游戏暂停
  pruseBtn() {
    // 播放音效
    // this.music._audioSource.playOneShot(this.music.clickAudio,0.5);
    if (!director.isPaused()) {
      director.pause(); //暂停游戏
      this.unschedule(() => {
        this.moveDown();
      });
      this.gamePruse.node.active = true;
    }
  }

  // 游戏继续
  resumeBtn() {
    director.resume(); //继续游戏
    this.schedule(() => {
      this.moveDown;
    }, 0.5); //开启计时器

    this.gamePruse.node.active = false;
  }

  // restart按钮
  restartBtn() {
    // 重新游戏
    director.loadScene("game");
    this.gameOver.node.active = false;
    // this.music._audioSource.playOneShot(this.music.clickAudio,0.5);
    console.log("游戏开始");
  }
}


